-- AlignM
-- create by zouyb
-- 对齐管理

module("AlignM", package.seeall);

frameSize = cc.Director:getInstance():getOpenGLView():getFrameSize();

-- 背景框尺寸样式
BG_SIZE_SMALL  = { ["width"] = 618, ["height"] = 272 };  -- CommonByPaperSmall.csd 对应的背景大小
BG_SIZE_NORMAL = { ["width"] = 618, ["height"] = 576 };  -- CommonByPaper.csd 对应的背景大小
BG_SIZE_LARGE  = { ["width"] = 602, ["height"] = 816 };  -- CommonBg.csd 对应的背景大小
BG_SIZE_COMMON = { ["width"] = 602, ["height"] = 567 };  -- CommonBg2.csd 对应的背景大小

-- 组件默认间距
DEFAULT_GAP = 20;

-- 默认的页眉、页脚边距
DEFAULT_MARGIN = 65;

-- 拉伸充满屏幕，一般用于背景图
function fitToScreen(node, name)
    local w = frameSize.width;
    local h = frameSize.height;

    -- 拉伸充满整个屏幕
    local bg = node:getChildByName(name);
    local bgImg = bg:getChildByName("bgImg");

    if tolua.type(bg) == "cc.Node" and bgImg then
        bg:setContentSize(w, h);
        bgImg:setContentSize(w, h);
        bg:setPosition(w / 2, h / 2);
    else
        bg:setContentSize(w, h);
        bg:setPosition(w / 2, h / 2);
    end
end

-- 顶部中间对齐， 并缩放到合适大小
function alignToTopCenter(node, name)
    local w = frameSize.width;
    local h = frameSize.height;
    local scale = math.min(w / DESIGN_WIDTH, h / DESIGN_HEIGHT);

    local TOP = node:getChildByName(name);
    TOP:setPosition(w / 2, h);
    TOP:setScale(scale);
end

-- 底部中间对齐， 并缩放到合适大小
function alignToBottomCenter(node, name)
    local w = frameSize.width;
    local h = frameSize.height;
    local scale = math.min(w / DESIGN_WIDTH, h / DESIGN_HEIGHT);

    local BT = node:getChildByName(name);
    BT:setPosition(w / 2, 0);
    BT:setScale(scale);
end

-- 中心对齐， 并缩放到合适大小
function alignToCenter(node, name)
    local w = frameSize.width;
    local h = frameSize.height;
    local scale = math.min(w / DESIGN_WIDTH, h / DESIGN_HEIGHT);

    local CT = node:getChildByName(name);
    CT:setPosition(w / 2, h / 2);
    CT:setScale(scale);
end

--------------------------------------------
-- 将两个组件横向并列排布，以中心对齐
-- @param node1 左边节点
-- @param node2 右边节点    要求两个节点锚点均为(0.5, 0.5), 且
-- @param gap   节点中间间隔
-- @param pos   节点要对齐的中心位置坐标
function alignNodesInHoriztal(node1, node2, gap, pos)
    local node1Width = node1:getContentSize().width * node1:getScale();
    local node2Width = node2:getContentSize().width * node2:getScale();

    if node1Width == 0 or node2Width == 0 then
        return;
    end

    node1:setPosition(pos);
    node2:setPosition(pos);

    node1:setPositionX(node1:getPositionX() - (node2Width + gap) / 2);
    node2:setPositionX(node2:getPositionX() + (node1Width + gap) / 2);
end

-- 获取自适应DEFAULT值
function getAdaptDefaultMargin()
    return DEFAULT_MARGIN;
end

---------------------------
-- 自适应组件布局（目前仅考虑纵向，暂不考虑横向）
-- @usage 请在设置好所有组件的内容后再调用此接口
-- @param bgNode       背景控件
-- @param bgSize       背景原始尺寸
-- @param nodeList     组件列表（按从上到下的顺序传入）
-- @param hGapList     各个组件的纵向间距（按从上到下的顺序传入，支持默认值）
-- @param topMargin    页眉边距（第一个组件与背景的边距，支持默认值）
-- @param bottomMargin 页脚边距（最后一个组件与背景的边距，支持默认值）
function adaptLayout(bgNode, bgSize, nodeList, hGapList, topMargin, bottomMargin)
    if type(nodeList) ~= "table" or #nodeList == 0 then
        -- 未传入任何组件
        return;
    end

    assert(bgNode ~= nil, "必须传入背景控件");
    assert(type(bgSize) == "table", "背景尺寸格式有误");

    -- 获取最后一个可见的组件
    local function getLastVisibleNode()
        local lastNode;
        for _, node in pairs(nodeList) do
            if node:isVisible() then
                lastNode = node;
            end
        end
        return lastNode;
    end

    local lastNode = getLastVisibleNode();
    if lastNode == nil then
        -- 没有一个组件是可见的？什么都不做
        return;
    end

    -- 页眉边距
    topMargin = topMargin or DEFAULT_MARGIN;

    -- 页脚边距
    if bottomMargin == nil then
        if isButton(lastNode) then
            bottomMargin = DEFAULT_MARGIN - 20;
        else
            bottomMargin = DEFAULT_MARGIN + 10;
        end
    end

    local bgHeight  = bgSize.height;
    local oldHeight = bgHeight*bgNode:getScaleY();

    -- 初始化背景的高度
    local totalHeight = topMargin + bottomMargin;
    local firstNode = nodeList[1];

    -- 加上第一个组件的高度
    totalHeight = totalHeight + getRealContentSize(firstNode).height;
    local nodeCount = #nodeList;

    if nodeCount == 1 then
        bgNode:setScaleY(totalHeight/bgHeight);
        return;
    end

    -- 每个组件默认的纵向间距
    local defaultGap = DEFAULT_GAP;
    local function getGap(index)
        if type(hGapList) == 'table' and
           type(hGapList[index]) == 'number' then
            return hGapList[index];
        end

        -- 如果是按钮，则它与上一个组件的间距要略大些
        if isButton(nodeList[index + 1]) then
            return 1.5*defaultGap;
        end

        return defaultGap;
    end

    -- 先计算出背景的高度
    -- 背景的高度  = 页眉边距 + 所有组件的高度 + 所有组件的纵向间距 + 页脚的边距
    for i = 2, nodeCount do
        local node = nodeList[i];

        -- 仅统计可见的组件
        if node:isVisible() then
            -- 加上各个组件的高度和间距
            totalHeight = totalHeight + getRealContentSize(node).height;

            local gap = getGap(i - 1);

            totalHeight = totalHeight + gap;
        end
    end

    -- 拉伸背景
    local scaleY = totalHeight/bgHeight;
    bgNode:setScaleY(scaleY);

    -- 第一个组件的纵坐标
    local height = getRealContentSize(firstNode).height;
    local achorY = firstNode:getAnchorPoint().y;
    local delta = bgNode:getPositionY();
    local posY = delta + totalHeight/2 - topMargin - height*(1 - achorY);
    firstNode:setPositionY(posY);
    local preNode = firstNode;
    for i = 2, nodeCount do
        local node = nodeList[i];

        -- 仅处理可见的组件
        if node:isVisible() then
            local gap = getGap(i - 1);

            local prePosY     = preNode:getPositionY();
            local preHeight   = getRealContentSize(preNode).height;
            local preAnchorY  = preNode:getAnchorPoint().y;
            local nextHeight  = getRealContentSize(node).height;
            local nextAnchorY = node:getAnchorPoint().y;

            local nextPosY = prePosY - preHeight*preAnchorY - gap - nextHeight*(1 - nextAnchorY);
            node:setPositionY(nextPosY);

            preNode = node;
        end
    end
end

-- 对页面的角标做适配
function adaptSubBg(bgNode, bgSize, bgScale)
    -- 根据适配后的界面高度比例，对界面上的角标位置进行修正
    local initBgScale = bgScale or 1;
    local initBgSize  = bgSize or BG_SIZE_NORMAL;
    local bg  = findChildByName(bgNode, "CT/bg_frame") or findChildByName(bgNode, "CT/bg");
    local bg1 = findChildByName(bgNode, "CT/sub_bg_l");
    local bg2 = findChildByName(bgNode, "CT/sub_bg_r");

    if not bg or not bg1 or not bg2 then
        -- 如果没有角标，就不做适配了
        return;
    end

    -- 这里要注意一下，有的原始模版高度并不是100%，所以增加了一个bgScale的参数。。
    local initFixY = initBgSize.height * (initBgScale - bg:getScaleY()) / 2;
    local fixY, deltaY = math.modf(initFixY);

    -- 由于缩放的问题，增加一个额外的修正值
    local fixCo = 0;
    if bg:getScaleY() / initBgScale > 0.9 then
        fixCo = 1;
    else
        fixCo = 5;
    end

    -- 四舍五入
    if math.abs(deltaY) > 0.5 then
        if fixY < 0 then
            -- 负值向上取整
            fixY = math.ceil(initFixY);
        else
            fixY = math.floor(initFixY);
        end
    else
        if fixY > 0 then
            -- 正值向上取整
            fixY = math.ceil(initFixY);
        else
            fixY = math.floor(initFixY);
        end
    end

    fixY = fixY - fixCo;

    bg1:setPositionY(bg1:getPositionY() - fixY);
    bg2:setPositionY(bg2:getPositionY() - fixY);
end
